using System.Text.Json;
using System.Text.Json.Serialization;

namespace Sage.CloudStorage.Qiniu.Models
{
    /// <summary>
    /// 七牛云上传策略类
    /// 用于配置文件上传的各种参数和限制条件，是上传凭证的核心组成部分
    /// </summary>
    /// <remarks>
    /// **上传策略概述**：
    /// 上传策略是资源上传时附带的一组配置设定，通过这组配置信息，
    /// 七牛云存储可以了解用户上传的需求和限制条件。
    /// 
    /// **主要功能**：
    /// - **目标控制**：指定上传目标空间和资源键
    /// - **时效管理**：设置上传凭证有效期
    /// - **结果处理**：配置上传结果的处理方式（回调或重定向）
    /// - **文件限制**：设置文件大小和类型限制
    /// - **存储选项**：配置存储类型和覆盖选项
    /// - **数据处理**：配置上传后的自动数据处理
    /// 
    /// **参考文档**：
    /// 详细文档参考：七牛云官方文档 - 上传策略
    /// https://developer.qiniu.com/kodo/manual/1206/put-policy
    /// 
    /// **使用流程**：
    /// 1. 创建UploadPolicy对象
    /// 2. 设置必需和可选参数
    /// 3. 调用ToJson()方法序列化为JSON
    /// 4. 用于生成上传凭证
    /// 5. 客户端使用凭证上传文件
    /// </remarks>
    public class UploadPolicy
    {
        #region 必需参数

        /// <summary>
        /// 指定上传的目标资源空间Bucket和资源键Key（最大为750字节）
        /// 这是上传策略中唯一的必需参数
        /// </summary>
        /// <remarks>
        /// **三种格式说明**：
        /// 
        /// 1. **&lt;bucket&gt;** - 存储桶模式
        ///    - 示例："my-bucket"
        ///    - 允许用户上传文件到指定的bucket
        ///    - 文件只能新增，不能覆盖
        ///    - 文件名由客户端指定或系统生成
        ///    - 适用场景：通用文件上传，用户头像上传等
        /// 
        /// 2. **&lt;bucket&gt;:&lt;key&gt;** - 精确模式
        ///    - 示例："my-bucket:documents/report.pdf"
        ///    - 只允许用户上传指定key的文件
        ///    - 默认允许修改同名文件（覆盖上传）
        ///    - 适用场景：配置文件更新，特定文件替换等
        /// 
        /// 3. **&lt;bucket&gt;:&lt;keyPrefix&gt;** - 前缀模式
        ///    - 示例："my-bucket:users/123/"
        ///    - 只允许用户上传指定前缀的文件
        ///    - 需要设置IsPrefixalScope=1
        ///    - 适用场景：用户目录上传，按分类组织文件等
        /// 
        /// **注意事项**：
        /// - 长度不能超过750字节
        /// - 必须是有效的UTF-8编码
        /// - 存储桶名称必须已存在
        /// - 资源键不能以"/"开头
        /// </remarks>
        [JsonPropertyName("scope")]
        public string Scope { get; set; } = string.Empty;

        /// <summary>
        /// 上传凭证有效截止时间（Unix时间戳，单位为秒）
        /// 这是上传策略中的另一个关键参数
        /// </summary>
        /// <remarks>
        /// **时间说明**：
        /// - 该截止时间为上传完成后，在七牛空间生成文件的校验时间
        /// - 不是上传开始时间，而是上传任务必须完成的时间
        /// - 使用Unix时间戳格式（自1970年1月1日以来的秒数）
        /// 
        /// **设置建议**：
        /// - 一般建议设置为上传开始时间 + 3600s（1小时）
        /// - 大文件上传建议适当延长时间
        /// - 批量上传场景建议设置更长的有效期
        /// - 临时上传链接可以设置较短的有效期
        /// 
        /// **计算示例**：
        /// ```csharp
        /// // 设置1小时有效期
        /// policy.Deadline = (uint)DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeSeconds();
        /// 
        /// // 设置24小时有效期
        /// policy.Deadline = (uint)DateTimeOffset.UtcNow.AddDays(1).ToUnixTimeSeconds();
        /// ```
        /// 
        /// **安全考虑**：
        /// - 有效期过长可能增加安全风险
        /// - 有效期过短可能影响大文件上传
        /// - 建议根据实际业务需求合理设置
        /// </remarks>
        [JsonPropertyName("deadline")]
        public uint Deadline { get; set; }

        #endregion

        #region 上传行为控制

        /// <summary>
        /// 若为1，表示允许用户上传以scope的keyPrefix为前缀的文件
        /// 配合scope的第三种格式使用
        /// </summary>
        /// <remarks>
        /// **前缀模式控制**：
        /// - 设置为1时，启用前缀模式上传
        /// - scope必须是"bucket:prefix"格式
        /// - 用户只能上传以指定前缀开头的文件
        /// 
        /// 适用场景：
        /// - 用户目录隔离：users/123/
        /// - 项目文件管理：projects/alpha/
        /// - 按时间组织：2024/03/
        /// - 内容分类：images/、documents/
        /// </remarks>
        [JsonPropertyName("isPrefixalScope")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public int? IsPrefixalScope { get; set; }

        /// <summary>
        /// 限定为新增语意，如果设置为非0值，则无论scope设置为什么形式，仅能以新增模式上传文件
        /// </summary>
        /// <remarks>
        /// **覆盖控制机制**：
        /// - 设置为0或null（默认）：允许覆盖同名文件
        /// - 设置为1：仅允许新增，禁止覆盖同名文件
        /// 
        /// **业务场景**：
        /// - **允许覆盖**：配置文件更新，头像替换，版本升级
        /// - **禁止覆盖**：历史文档保存，日志文件上传，备份文件
        /// 
        /// **行为说明**：
        /// - 当文件已存在且内容相同时，上传仍然返回成功
        /// - 当文件已存在且内容不同时，上传返回失败
        /// - 此设置对所有scope格式都有效
        /// </remarks>
        [JsonPropertyName("insertOnly")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public int? InsertOnly { get; set; }

        #endregion

        #region 用户标识和文件命名

        /// <summary>
        /// 唯一属主标识。特殊场景下非常有用，例如根据App-Client标识给图片或视频打水印
        /// </summary>
        /// <remarks>
        /// **用户标识用途**：
        /// - 多租户系统中区分不同用户
        /// - 为用户内容添加水印或标识
        /// - 统计和分析用户上传行为
        /// - 实现基于用户的访问控制
        /// 
        /// **使用示例**：
        /// - 用户ID："user_12345"
        /// - 应用客户端标识："app_ios_v2.1"
        /// - 设备标识："device_iphone_x"
        /// </remarks>
        [JsonPropertyName("endUser")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? EndUser { get; set; }

        /// <summary>
        /// saveKey的优先级设置
        /// 控制是否强制使用saveKey进行文件命名
        /// </summary>
        /// <remarks>
        /// **命名优先级**：
        /// - **false（默认）**：saveKey仅在客户端未指定key时生效
        /// - **true**：忽略客户端指定的key，强制使用saveKey命名
        /// 
        /// **使用场景**：
        /// - 统一文件命名规范
        /// - 防止客户端恶意命名
        /// - 实现自动化文件组织
        /// - 确保文件名的唯一性
        /// 
        /// **注意事项**：
        /// - 设置为true时，saveKey不能为空
        /// - 客户端指定的文件名将被完全忽略
        /// </remarks>
        [JsonPropertyName("forceSaveKey")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public bool? ForceSaveKey { get; set; }

        /// <summary>
        /// 自定义资源名，支持魔法变量和自定义变量
        /// </summary>
        /// <remarks>
        /// 🪄 **魔法变量支持**：
        /// - **$(key)**：原始文件名
        /// - **$(fname)**：上传文件的原始文件名
        /// - **$(ext)**：文件扩展名
        /// - **$(etag)**：文件的hash值
        /// - **$(uuid)**：随机UUID
        /// - **$(timestamp)**：时间戳
        /// - **$(year)**、**$(mon)**、**$(day)**：日期相关
        /// 
        /// **命名模板示例**：
        /// ```
        /// "users/$(endUser)/$(year)/$(mon)/$(day)/$(uuid)$(ext)"
        /// "documents/$(timestamp)_$(fname)"
        /// "images/thumb_$(key)"
        /// ```
        /// 
        /// **最佳实践**：
        /// - 使用UUID确保文件名唯一性
        /// - 按日期组织便于管理和查询
        /// - 包含用户标识便于权限控制
        /// - 保留原始扩展名确保文件类型正确
        /// </remarks>
        [JsonPropertyName("saveKey")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? SaveKey { get; set; }

        #endregion

        #region 回调和重定向

        /// <summary>
        /// Web端文件上传成功后，浏览器执行303跳转的URL
        /// 主要用于表单上传场景
        /// </summary>
        /// <remarks>
        /// **Web表单上传**：
        /// - 适用于传统的HTML表单文件上传
        /// - 上传成功后浏览器会自动跳转到指定URL
        /// - 跳转URL格式：&lt;returnUrl&gt;?upload_ret=&lt;queryString&gt;
        /// - queryString包含returnBody的内容
        /// 
        /// **工作流程**：
        /// 1. 用户通过HTML表单上传文件
        /// 2. 文件上传成功到七牛云
        /// 3. 浏览器自动跳转到returnUrl
        /// 4. URL参数中包含上传结果信息
        /// 
        /// **注意事项**：
        /// - 如不设置returnUrl，则直接返回returnBody内容
        /// - 主要用于传统Web应用，现代应用较少使用
        /// - 需要确保returnUrl是可访问的有效URL
        /// </remarks>
        [JsonPropertyName("returnUrl")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? ReturnUrl { get; set; }

        /// <summary>
        /// 上传成功后，自定义七牛云最终返回给上传端的数据
        /// 支持魔法变量和自定义变量，要求是合法的JSON文本
        /// </summary>
        /// <remarks>
        /// **返回内容定制**：
        /// - 必须是合法的JSON格式
        /// - 支持魔法变量获取文件信息
        /// - 可以包含自定义的业务数据
        /// - 直接返回给客户端，无需额外请求
        /// 
        /// 🪄 **常用魔法变量**：
        /// - **$(key)**：文件的资源键
        /// - **$(etag)**：文件的hash值
        /// - **$(fsize)**：文件大小
        /// - **$(mimeType)**：文件MIME类型
        /// - **$(imageInfo.width)**：图片宽度
        /// - **$(imageInfo.height)**：图片高度
        /// - **$(avinfo.video.duration)**：视频时长
        /// 
        /// **JSON示例**：
        /// ```json
        /// {
        ///   "success": true,
        ///   "key": "$(key)",
        ///   "hash": "$(etag)",
        ///   "size": $(fsize),
        ///   "width": $(imageInfo.width),
        ///   "height": $(imageInfo.height),
        ///   "uploadTime": "$(timestamp)"
        /// }
        /// ```
        /// 
        /// **使用建议**：
        /// - 只返回客户端需要的信息，避免冗余
        /// - 包含必要的业务标识信息
        /// - 注意JSON格式的正确性
        /// </remarks>
        [JsonPropertyName("returnBody")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? ReturnBody { get; set; }

        /// <summary>
        /// 上传成功后，七牛云向业务服务器发送POST请求的URL
        /// 必须是公网上可以正常访问并响应的有效URL
        /// </summary>
        /// <remarks>
        /// **回调机制**：
        /// - 上传成功后七牛云主动向指定URL发送POST请求
        /// - 可以设置多个回调URL，用分号(;)分隔
        /// - 前一个URL失败时会依次重试下一个URL
        /// - 回调请求超时时间通常为30秒
        /// 
        /// **业务场景**：
        /// - 文件上传后的业务逻辑处理
        /// - 数据库记录更新
        /// - 消息通知和推送
        /// - 后续数据处理任务触发
        /// - 上传统计和监控
        /// 
        /// **URL格式示例**：
        /// ```
        /// 单个回调：
        /// "https://api.example.com/upload/callback"
        /// 
        /// 多个回调（故障转移）：
        /// "https://api1.example.com/callback;https://api2.example.com/callback"
        /// ```
        /// 
        /// **重要要求**：
        /// - 指定callbackUrl时，必须同时指定callbackBody
        /// - 回调URL必须能正常接收POST请求
        /// - 建议实现幂等性处理，防止重复回调
        /// - 回调服务应该快速响应，避免超时
        /// </remarks>
        [JsonPropertyName("callbackUrl")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? CallbackUrl { get; set; }

        /// <summary>
        /// 上传成功后，七牛云向业务服务器发送回调通知时的Host值
        /// 与callbackUrl配合使用，仅当设置了callbackUrl时才有效
        /// </summary>
        /// <remarks>
        /// **Host头控制**：
        /// - 用于指定回调请求中的Host头部值
        /// - 在某些网络环境或代理配置中可能需要
        /// - 通常情况下不需要设置，使用默认值即可
        /// 
        /// **使用场景**：
        /// - 内网环境中的域名解析
        /// - 负载均衡器后的服务识别
        /// - 虚拟主机环境中的路由
        /// </remarks>
        [JsonPropertyName("callbackHost")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? CallbackHost { get; set; }

        /// <summary>
        /// 上传成功后，七牛云向业务服务器发送的回调请求体
        /// 支持魔法变量和自定义变量
        /// </summary>
        /// <remarks>
        /// **回调内容格式**：
        /// 回调内容的格式取决于callbackBodyType的设置：
        /// 
        /// **application/x-www-form-urlencoded格式**：
        /// ```
        /// key=$(key)&amp;hash=$(etag)&amp;size=$(fsize)&amp;width=$(imageInfo.width)
        /// ```
        /// 
        /// **application/json格式**：
        /// ```json
        /// {
        ///   "key": "$(key)",
        ///   "hash": "$(etag)",
        ///   "size": $(fsize),
        ///   "width": $(imageInfo.width)
        /// }
        /// ```
        /// 
        /// **魔法变量**：
        /// - 基本信息：$(key)、$(etag)、$(fsize)、$(mimeType)
        /// - 图片信息：$(imageInfo.width)、$(imageInfo.height)
        /// - 视频信息：$(avinfo.video.duration)、$(avinfo.video.bitrate)
        /// - 音频信息：$(avinfo.audio.duration)、$(avinfo.audio.bitrate)
        /// - 时间信息：$(timestamp)、$(year)、$(mon)、$(day)
        /// 
        /// **最佳实践**：
        /// - 只包含业务逻辑需要的信息
        /// - 使用JSON格式便于解析
        /// - 包含必要的标识信息用于业务处理
        /// </remarks>
        [JsonPropertyName("callbackBody")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? CallbackBody { get; set; }

        /// <summary>
        /// 上传成功后，七牛云向业务服务器发送回调通知callbackBody的Content-Type
        /// 决定回调请求体的格式
        /// </summary>
        /// <remarks>
        /// **支持的内容类型**：
        /// 
        /// **application/x-www-form-urlencoded（默认）**：
        /// - 传统的表单格式
        /// - 适合简单的键值对数据
        /// - 自动进行URL编码
        /// 
        /// **application/json**：
        /// - JSON格式，便于解析
        /// - 支持复杂的数据结构
        /// - 现代API的首选格式
        /// 
        /// **使用建议**：
        /// - 现代应用推荐使用application/json
        /// - callbackBody的格式必须与此设置匹配
        /// - 服务端需要相应地解析对应格式的数据
        /// </remarks>
        [JsonPropertyName("callbackBodyType")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? CallbackBodyType { get; set; }

        #endregion

        #region 数据处理

        /// <summary>
        /// 资源上传成功后触发执行预转持久化处理的任务类型
        /// 控制数据处理任务的执行优先级
        /// </summary>
        /// <remarks>
        /// **任务类型说明**：
        /// - **"0"（默认）**：普通任务，正常优先级执行
        /// - **"1"**：闲时任务，系统空闲时执行，成本较低
        /// 
        /// **成本考虑**：
        /// - 普通任务：实时处理，费用相对较高
        /// - 闲时任务：延迟处理，费用相对较低
        /// 
        /// **选择建议**：
        /// - 实时需求：选择普通任务
        /// - 批量处理：选择闲时任务
        /// - 成本敏感：优先选择闲时任务
        /// </remarks>
        [JsonPropertyName("persistentType")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? PersistentType { get; set; }

        /// <summary>
        /// 资源上传成功后触发执行的持久化处理指令列表
        /// 每个指令是一个API规格字符串，多个指令用分号分隔
        /// </summary>
        /// <remarks>
        /// **数据处理功能**：
        /// - **音视频转码**：格式转换、分辨率调整、码率控制
        /// - **图片处理**：缩放、裁剪、水印、格式转换
        /// - **文档转换**：PDF转图片、Office文档预览
        /// - **内容审核**：图片、视频、音频内容审核
        /// 
        /// **指令格式示例**：
        /// 
        /// **视频转码**：
        /// ```
        /// avthumb/mp4/vb/1000k/ab/128k|saveas/base64编码的保存路径
        /// ```
        /// 
        /// **图片处理**：
        /// ```
        /// imageView2/1/w/200/h/200|saveas/base64编码的保存路径
        /// ```
        /// 
        /// **多个处理（用分号分隔）**：
        /// ```
        /// avthumb/mp4|saveas/路径1;vframe/jpg/offset/1|saveas/路径2
        /// ```
        /// 
        /// **使用限制**：
        /// - fileType=2或3（归档存储或深度归档存储）时不支持
        /// - 处理结果会产生额外的存储和处理费用
        /// - 复杂处理可能需要较长处理时间
        /// 
        /// **最佳实践**：
        /// - 合理规划处理指令，避免不必要的处理
        /// - 使用saveas指令指定结果存储位置
        /// - 考虑处理时间对业务流程的影响
        /// </remarks>
        [JsonPropertyName("persistentOps")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? PersistentOps { get; set; }

        /// <summary>
        /// 资源上传成功后指定工作流模板即可执行媒体处理操作
        /// 与persistentOps二选一，不能同时设置
        /// </summary>
        /// <remarks>
        /// **工作流模板**：
        /// - 预定义的处理流程模板
        /// - 在七牛云控制台创建和管理
        /// - 包含完整的处理步骤和参数
        /// - 便于复用和标准化
        /// 
        /// **优势**：
        /// - 简化配置，避免复杂的指令编写
        /// - 统一标准，确保处理结果一致性
        /// - 便于管理，可视化配置和监控
        /// - 版本控制，支持模板版本管理
        /// 
        /// **互斥关系**：
        /// - persistentWorkflowTemplateID和persistentOps只能设置其中一个
        /// - 设置了工作流模板ID后，不能再设置persistentOps
        /// - 需要在七牛云控制台预先创建工作流模板
        /// </remarks>
        [JsonPropertyName("persistentWorkflowTemplateID")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? PersistentWorkflowTemplateID { get; set; }

        /// <summary>
        /// 接收持久化处理结果通知的URL
        /// 处理完成后七牛云会向此URL发送处理结果
        /// </summary>
        /// <remarks>
        /// **结果通知**：
        /// - 数据处理完成后主动通知业务服务器
        /// - 包含处理结果、状态、错误信息等
        /// - 支持业务系统及时获取处理结果
        /// 
        /// **通知内容**：
        /// - 处理状态（成功/失败）
        /// - 处理结果文件信息
        /// - 处理耗时和资源消耗
        /// - 错误信息（如果处理失败）
        /// 
        /// **实现要求**：
        /// - 接收POST请求
        /// - 返回200状态码表示接收成功
        /// - 实现幂等性处理
        /// - 处理异常情况和重试机制
        /// </remarks>
        [JsonPropertyName("persistentNotifyUrl")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? PersistentNotifyUrl { get; set; }

        /// <summary>
        /// 转码队列名，仅适用于普通任务
        /// 闲时任务不能指定队列
        /// </summary>
        /// <remarks>
        /// **队列管理**：
        /// - 控制处理任务的执行队列
        /// - 不同队列可能有不同的处理能力和优先级
        /// - 仅对普通任务（persistentType="0"）有效
        /// 
        /// **使用场景**：
        /// - 任务优先级控制
        /// - 资源隔离和分配
        /// - 处理能力规划
        /// - 成本控制
        /// 
        /// **限制说明**：
        /// - 队列名需要在七牛云控制台预先配置
        /// - 闲时任务自动分配队列，不能手动指定
        /// - 不同队列可能有不同的计费规则
        /// </remarks>
        [JsonPropertyName("persistentPipeline")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? PersistentPipeline { get; set; }

        #endregion

        #region 文件限制

        /// <summary>
        /// 限定上传文件大小最小值，单位字节
        /// 小于此限制的文件上传将失败，返回400状态码
        /// </summary>
        /// <remarks>
        /// **最小值限制用途**：
        /// - 防止上传空文件或过小文件
        /// - 确保文件内容的有效性
        /// - 避免恶意上传大量小文件
        /// 
        /// **使用场景**：
        /// - 图片上传：确保图片有足够的像素
        /// - 文档上传：确保文档有实际内容
        /// - 媒体文件：确保音视频有足够时长
        /// 
        /// **注意事项**：
        /// - 设置过大可能影响正常文件上传
        /// - 需要考虑不同文件类型的特点
        /// - 建议根据业务需求合理设置
        /// </remarks>
        [JsonPropertyName("fsizeMin")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public long? FsizeMin { get; set; }

        /// <summary>
        /// 限定上传文件大小最大值，单位字节
        /// 超过此限制的文件上传将失败，返回413状态码
        /// </summary>
        /// <remarks>
        /// **最大值限制用途**：
        /// - 控制存储成本和带宽消耗
        /// - 防止恶意上传超大文件
        /// - 确保系统稳定性和性能
        /// 
        /// **推荐设置**：
        /// - 头像图片：1-5MB
        /// - 普通图片：10-50MB
        /// - 文档文件：50-100MB
        /// - 音频文件：100-500MB
        /// - 视频文件：500MB-5GB
        /// 
        /// **大小计算**：
        /// ```csharp
        /// // 10MB限制
        /// policy.FsizeLimit = 10 * 1024 * 1024;
        /// 
        /// // 100MB限制
        /// policy.FsizeLimit = 100L * 1024 * 1024;
        /// 
        /// // 1GB限制
        /// policy.FsizeLimit = 1024L * 1024 * 1024;
        /// ```
        /// </remarks>
        [JsonPropertyName("fsizeLimit")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public long? FsizeLimit { get; set; }

        /// <summary>
        /// 限定用户上传的文件类型
        /// 指定后，七牛服务器会检测文件内容判断MIME类型，匹配失败返回403状态码
        /// </summary>
        /// <remarks>
        /// **MIME类型检测**：
        /// - 七牛云会检测实际文件内容，不仅仅依赖文件扩展名
        /// - 检测结果与指定值匹配才允许上传
        /// - 提供更可靠的文件类型验证
        /// 
        /// **格式说明**：
        /// 
        /// **通配符格式**：
        /// - `"image/*"` - 允许所有图片类型
        /// - `"video/*"` - 允许所有视频类型
        /// - `"audio/*"` - 允许所有音频类型
        /// 
        /// **精确类型（用分号分隔）**：
        /// - `"image/jpeg;image/png"` - 只允许JPEG和PNG图片
        /// - `"application/pdf;application/msword"` - 只允许PDF和Word文档
        /// 
        /// **排除格式（感叹号开头）**：
        /// - `"!application/json;text/plain"` - 禁止JSON和纯文本文件
        /// 
        /// **常用MIME类型**：
        /// - 图片：image/jpeg, image/png, image/gif, image/webp
        /// - 文档：application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document
        /// - 视频：video/mp4, video/avi, video/quicktime
        /// - 音频：audio/mpeg, audio/wav, audio/ogg
        /// 
        /// **安全建议**：
        /// - 根据业务需求严格限制文件类型
        /// - 避免上传可执行文件和脚本文件
        /// - 结合文件大小限制提供全面保护
        /// </remarks>
        [JsonPropertyName("mimeLimit")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? MimeLimit { get; set; }

        #endregion

        #region 存储和检测设置

        /// <summary>
        /// 开启MimeType侦测功能
        /// 控制如何确定上传文件的MIME类型
        /// </summary>
        /// <remarks>
        /// **检测模式说明**：
        /// 
        /// **值为1**：强制内容检测模式
        /// - 忽略上传端传递的MimeType信息
        /// - 检测顺序：内容检测 → 文件扩展名 → Key扩展名
        /// - 最准确但耗时稍长
        /// 
        /// **值为0（默认）**：智能检测模式
        /// - 如果上传端指定了MimeType（非application/octet-stream）则直接使用
        /// - 否则检测顺序：文件扩展名 → Key扩展名 → 内容检测
        /// - 平衡准确性和性能
        /// 
        /// **值为-1**：完全信任模式
        /// - 完全使用上传端指定的MimeType值
        /// - 不进行任何检测和修正
        /// - 性能最好但可能不准确
        /// 
        /// **使用建议**：
        /// - 对文件类型准确性要求高：设置为1
        /// - 一般业务场景：使用默认值0
        /// - 性能要求极高且信任上传端：设置为-1
        /// </remarks>
        [JsonPropertyName("detectMime")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public int? DetectMime { get; set; }

        /// <summary>
        /// 文件存储类型
        /// 控制文件在七牛云中的存储策略和成本
        /// </summary>
        /// <remarks>
        /// **存储类型说明**：
        /// 
        /// **0 - 标准存储（默认）**：
        /// - 高可用、低延迟
        /// - 适合频繁访问的文件
        /// - 成本相对较高
        /// 
        /// **1 - 低频存储**：
        /// - 较低成本，适中延迟
        /// - 适合访问频率较低的文件
        /// - 有最小存储时间要求
        /// 
        /// **2 - 归档存储**：
        /// - 成本很低，但访问需要解冻
        /// - 适合长期保存的文件
        /// - 解冻时间：几分钟到几小时
        /// 
        /// **3 - 深度归档存储**：
        /// - 成本最低，解冻时间最长
        /// - 适合极少访问的长期存档
        /// - 解冻时间：几小时到几天
        /// 
        /// **4 - 归档直读存储**：
        /// - 归档成本，但支持直接读取
        /// - 平衡成本和访问性能
        /// 
        /// **5 - 智能分层存储**：
        /// - 自动根据访问模式调整存储类型
        /// - 智能优化成本和性能
        /// 
        /// **成本考虑**：
        /// - 存储成本：标准 > 低频 > 归档直读 > 归档 > 深度归档
        /// - 访问成本：深度归档 > 归档 > 低频 > 标准
        /// - 选择存储类型需要综合考虑访问频率和成本
        /// </remarks>
        [JsonPropertyName("fileType")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public int? FileType { get; set; }

        /// <summary>
        /// 上传请求单链接速度限制，控制客户端带宽占用
        /// 单位为bit/s，取值范围为819200~838860800（100KB/s~100MB/s）
        /// </summary>
        /// <remarks>
        /// **带宽控制用途**：
        /// - 防止单个上传占用过多带宽
        /// - 确保多用户环境下的公平使用
        /// - 控制网络资源消耗
        /// - 避免网络拥塞
        /// 
        /// **速度换算**：
        /// ```
        /// 100 KB/s = 819,200 bit/s
        /// 1 MB/s = 8,388,608 bit/s
        /// 10 MB/s = 83,886,080 bit/s
        /// 100 MB/s = 838,860,800 bit/s
        /// ```
        /// 
        /// **设置建议**：
        /// - 移动网络：限制在1-5MB/s
        /// - 普通宽带：限制在5-20MB/s
        /// - 企业网络：根据实际带宽合理设置
        /// - 不设置则不限速
        /// 
        /// **注意事项**：
        /// - 限速过低会影响用户体验
        /// - 限速过高可能无实际效果
        /// - 建议根据目标用户的网络环境设置
        /// </remarks>
        [JsonPropertyName("trafficLimit")]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public long? TrafficLimit { get; set; }

        #endregion

        #region 实用方法

        /// <summary>
        /// 将上传策略转换为JSON字符串
        /// 使用源生成器进行序列化，提供最佳性能
        /// </summary>
        /// <returns>JSON格式的上传策略字符串</returns>
        /// <remarks>
        /// **序列化特点**：
        /// - 使用System.Text.Json源生成器，性能优异
        /// - 自动忽略null值，减少JSON大小
        /// - 使用camelCase命名策略，符合JSON规范
        /// - 不进行格式化，减少传输大小
        /// 
        /// **输出示例**：
        /// ```json
        /// {
        ///   "scope": "my-bucket",
        ///   "deadline": 1640995200,
        ///   "fsizeLimit": 10485760,
        ///   "mimeLimit": "image/*"
        /// }
        /// ```
        /// 
        /// **使用场景**：
        /// - 生成上传凭证
        /// - 策略内容验证
        /// - 调试和日志输出
        /// - API参数传递
        /// </remarks>
        public string ToJson()
        {
            return JsonSerializer.Serialize(this, QiniuJsonSerializerContext.Default.UploadPolicy);
        }

        #endregion

        #region 静态工厂方法

        /// <summary>
        /// 创建一个基本的上传策略
        /// 只设置必需的参数，适合简单的上传场景
        /// </summary>
        /// <param name="bucket">存储空间名称</param>
        /// <param name="expireInSeconds">过期时间（秒），默认3600秒（1小时）</param>
        /// <returns>配置好基本参数的上传策略实例</returns>
        /// <exception cref="ArgumentException">当bucket为空或expireInSeconds无效时抛出</exception>
        /// <remarks>
        /// **基本策略特点**：
        /// - 只设置必需的scope和deadline参数
        /// - 允许上传到指定存储空间的任意位置
        /// - 使用insertOnly模式，不允许覆盖
        /// - 适合大部分通用上传场景
        /// 
        /// **使用示例**：
        /// ```csharp
        /// // 创建1小时有效期的基本策略
        /// var policy = UploadPolicy.CreateBasicPolicy("my-bucket");
        /// 
        /// // 创建6小时有效期的基本策略
        /// var longPolicy = UploadPolicy.CreateBasicPolicy("my-bucket", 21600);
        /// ```
        /// 
        /// **适用场景**：
        /// - 用户头像上传
        /// - 图片素材上传
        /// - 文档文件上传
        /// - 其他不需要特殊配置的上传
        /// </remarks>
        public static UploadPolicy CreateBasicPolicy(string bucket, int expireInSeconds = 3600)
        {
            if (string.IsNullOrEmpty(bucket))
                throw new ArgumentException("存储空间名称不能为空", nameof(bucket));

            if (expireInSeconds <= 0)
                throw new ArgumentException("过期时间必须大于0", nameof(expireInSeconds));

            // 计算过期时间戳（当前时间 + 过期秒数）
            var deadline = (uint)DateTimeOffset.UtcNow.AddSeconds(expireInSeconds).ToUnixTimeSeconds();

            return new UploadPolicy
            {
                Scope = bucket,
                Deadline = deadline
            };
        }

        /// <summary>
        /// 创建指定资源键的上传策略
        /// 只允许上传到指定的完整路径，提供精确控制
        /// </summary>
        /// <param name="bucket">存储空间名称</param>
        /// <param name="key">资源键名（完整文件路径）</param>
        /// <param name="expireInSeconds">过期时间（秒），默认3600秒（1小时）</param>
        /// <param name="insertOnly">是否仅允许新增，不允许覆盖，默认false</param>
        /// <returns>配置好的指定键上传策略实例</returns>
        /// <exception cref="ArgumentException">当参数无效时抛出</exception>
        /// <remarks>
        /// **指定键策略特点**：
        /// - 精确控制上传文件的存储位置
        /// - 可以选择是否允许覆盖已存在文件
        /// - 适合需要明确文件路径的场景
        /// - 提供更强的安全控制
        /// 
        /// **使用示例**：
        /// ```csharp
        /// // 允许覆盖的精确上传
        /// var policy = UploadPolicy.CreateKeyPolicy("my-bucket", "documents/report.pdf");
        /// 
        /// // 不允许覆盖的新增上传
        /// var insertPolicy = UploadPolicy.CreateKeyPolicy(
        ///     "my-bucket", "logs/app.log", 3600, true);
        /// ```
        /// 
        /// **适用场景**：
        /// - 配置文件更新
        /// - 系统文件替换
        /// - 版本文件发布
        /// - 特定位置的文件上传
        /// </remarks>
        public static UploadPolicy CreateKeyPolicy(string bucket, string key, int expireInSeconds = 3600, bool insertOnly = false)
        {
            if (string.IsNullOrEmpty(bucket))
                throw new ArgumentException("存储空间名称不能为空", nameof(bucket));

            if (string.IsNullOrEmpty(key))
                throw new ArgumentException("资源键名不能为空", nameof(key));

            if (expireInSeconds <= 0)
                throw new ArgumentException("过期时间必须大于0", nameof(expireInSeconds));

            // 计算过期时间戳（当前时间 + 过期秒数）
            var deadline = (uint)DateTimeOffset.UtcNow.AddSeconds(expireInSeconds).ToUnixTimeSeconds();

            var policy = new UploadPolicy
            {
                Scope = $"{bucket}:{key}",
                Deadline = deadline
            };

            if (insertOnly)
                policy.InsertOnly = 1;

            return policy;
        }

        /// <summary>
        /// 创建指定前缀的上传策略
        /// 只允许上传到指定前缀开头的路径，提供目录级别的控制
        /// </summary>
        /// <param name="bucket">存储空间名称</param>
        /// <param name="keyPrefix">资源键前缀（目录路径）</param>
        /// <param name="expireInSeconds">过期时间（秒），默认3600秒（1小时）</param>
        /// <returns>配置好的前缀上传策略实例</returns>
        /// <exception cref="ArgumentException">当参数无效时抛出</exception>
        /// <remarks>
        /// **前缀策略特点**：
        /// - 限制上传到指定目录或前缀
        /// - 在前缀范围内可以自由命名文件
        /// - 自动设置isPrefixalScope标志
        /// - 适合目录级别的权限控制
        /// 
        /// **前缀示例**：
        /// - `"users/123/"` - 用户123的个人目录
        /// - `"projects/alpha/"` - alpha项目的文件目录
        /// - `"images/2024/03/"` - 2024年3月的图片目录
        /// - `"temp/"` - 临时文件目录
        /// 
        /// **使用示例**：
        /// ```csharp
        /// // 用户个人目录上传
        /// var userPolicy = UploadPolicy.CreatePrefixPolicy("files", "users/12345/");
        /// 
        /// // 项目文件目录上传
        /// var projectPolicy = UploadPolicy.CreatePrefixPolicy("workspace", "projects/web/");
        /// 
        /// // 按日期分类的上传
        /// var datePolicy = UploadPolicy.CreatePrefixPolicy("images", "2024/03/15/");
        /// ```
        /// 
        /// 💡 **适用场景**：
        /// - 多用户系统的文件隔离
        /// - 按项目或模块组织文件
        /// - 按时间分类存储文件
        /// - 多租户系统的空间划分
        /// </remarks>
        public static UploadPolicy CreatePrefixPolicy(string bucket, string keyPrefix, int expireInSeconds = 3600)
        {
            if (string.IsNullOrEmpty(bucket))
                throw new ArgumentException("存储空间名称不能为空", nameof(bucket));

            if (string.IsNullOrEmpty(keyPrefix))
                throw new ArgumentException("资源键前缀不能为空", nameof(keyPrefix));

            if (expireInSeconds <= 0)
                throw new ArgumentException("过期时间必须大于0", nameof(expireInSeconds));

            // 计算过期时间戳（当前时间 + 过期秒数）
            var deadline = (uint)DateTimeOffset.UtcNow.AddSeconds(expireInSeconds).ToUnixTimeSeconds();

            return new UploadPolicy
            {
                Scope = $"{bucket}:{keyPrefix}",
                IsPrefixalScope = 1,
                Deadline = deadline
            };
        }

        #endregion
    }
}
